﻿using IKapBoardClassLibrary;
using System;
using System.Runtime.InteropServices;

namespace Camera
{
    public class CameraIKap : CameraBase
    {
        // Frame Grabber parameters
        private IntPtr m_hBoard;                             // Frame grabber device handle 
        private int m_nCurFrameIndex;                                         // Current grab frame index
        private int m_nTotalFrameCount;                                     // Total frame count
        private string resourceIndex;

        public override event ReadImageDelegate ReadImageEvent;
        public override event ConnectLossDelegate ConnectLossEvent;

        #region Callback
        private delegate void IKapCallBackProc(IntPtr pParam);
        private IKapCallBackProc OnGrabStartProc;
        private IKapCallBackProc OnFrameLostProc;
        private IKapCallBackProc OnTimeoutProc;
        private IKapCallBackProc OnFrameReadyProc;
        private IKapCallBackProc OnGrabStopProc;
        private IKapCallBackProc OnGrabLineEndProc;
        private IKapCallBackProc OnGeneralInput1FallingEdgeProc;
        private IKapCallBackProc OnGeneralInput1RisingEdgeProc;
        private IKapCallBackProc OnGeneralInput2FallingEdgeProc;
        private IKapCallBackProc OnGeneralInput2RisingEdgeProc;
        #endregion

        public CameraIKap()
        {
            m_hBoard = new IntPtr(-1);
            m_nCurFrameIndex = 0;
            m_nTotalFrameCount = 5;
        }

        public static string[] DeviceListAcq()
        {
            uint nPCIeDevCount = 0;
            // Get the count of PCIe interface boards
            IKapBoard.IKapGetBoardCount((int)BoardType.IKBoardPCIE, ref nPCIeDevCount);
            if (nPCIeDevCount == 0)
            {
                return null;
            }
            string[] deviceList = new string[nPCIeDevCount];
            for (uint i = 0; i < nPCIeDevCount; ++i)
            {
                deviceList[i] = i.ToString();
            }
            return deviceList;
        }

        #region Callback
        // This callback function will be called on grab start
        private void OnGrabStartFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on frame lost
        private void OnFrameLostFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on grabbing timeout
        private void OnTimeoutFunc(IntPtr pParam)
        {

        }

        // This callback function will be called at the frame ready
        private void OnFrameReadyFunc(IntPtr pParam)
        {
            IKapBoard.IKAPBUFFERSTATUS status = new IKapBoard.IKAPBUFFERSTATUS();
            IKapBoard.IKapGetBufferStatus(pParam, m_nCurFrameIndex, ref status);
            if (status.uFull == 1)
            {
                IntPtr pUserBuffer = IntPtr.Zero;
                int nWidth = 0;
                int nHeight = 0;
                // get frame grabber buffer
                IKapBoard.IKapGetBufferAddress(pParam, m_nCurFrameIndex, ref pUserBuffer);
                // Get image width
                IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_WIDTH, ref nWidth);
                // Get image height
                IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_HEIGHT, ref nHeight);
                //HOperatorSet.GenImage1(out HObject image, "byte", nWidth, nHeight, pUserBuffer);
                Imgdata imgdata = new Imgdata
                {
                    data = pUserBuffer,
                    width = nWidth,
                    height = nHeight
                };
                ReadImageEvent(imgdata);
            }
            ++m_nCurFrameIndex;
            m_nCurFrameIndex %= m_nTotalFrameCount;
        }

        // This callback function will be called on grab stop
        private void OnGrabStopFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on grab line end
        private void OnGrabLineEndFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on General Input 1 Falling Edge
        private void OnGeneralInput1FallingEdgeFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on General Input 1 Rising Edge
        private void OnGeneralInput1RisingEdgeFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on General Input 2 Falling Edge
        private void OnGeneralInput2FallingEdgeFunc(IntPtr pParam)
        {

        }

        // This callback function will be called on General Input 2 Rising Edge
        private void OnGeneralInput2RisingEdgeFunc(IntPtr pParam)
        {

        }
        #endregion

        public override bool Open(string resourceIndex)
        {
            this.resourceIndex = resourceIndex;
            m_hBoard = IKapBoard.IKapOpen((int)BoardType.IKBoardPCIE, uint.Parse(resourceIndex));
            return !m_hBoard.Equals(-1);
        }

        // This function will be unregister callback
        private void UnRegisterCallback()
        {
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStart);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameReady);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameLost);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_TimeOut);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStop);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_INPUT_FALLING_EDGE + 0x02);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEVENT_INPUT_RISING_EDGE + 0x02);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_INPUT_FALLING_EDGE + 0x04);
            IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEVENT_INPUT_RISING_EDGE + 0x04);
        }

        // This function will be close device and release buffer
        private void CloseDevice()
        {
            // Close frame grabber
            if (!m_hBoard.Equals(-1))
            {
                IKapBoard.IKapClose(m_hBoard);
                m_hBoard = (IntPtr)(-1);
            }
        }

        public override bool Close()
        {
            UnRegisterCallback();
            CloseDevice();
            return true;
        }

        public override bool StartGrab()
        {
            // Start capturing image
            IKapBoard.IKapStartGrab(m_hBoard, 0);
            return true;
        }

        public override void StopGrab()
        {
            // Stop capturing image
            IKapBoard.IKapStopGrab(m_hBoard);
        }

        public override void SetTriggerMode(TriggerMode triggerMode)
        {

        }

        public override void SetTriggerSource(TriggerSource triggerSource)
        {

        }

        public override bool TriggerSoftware()
        {
            return true;
        }

        public override string GetSerialNumber()
        {
            return resourceIndex;
        }

        public override double GetParameter(string uType)
        {
            int npValue = 0;
            switch (uType)
            {
                case "IKP_IMAGE_WIDTH":
                    // Get image width
                    IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_WIDTH, ref npValue);
                    break;
                case "IKP_IMAGE_HEIGHT":
                    // Get image height
                    IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_HEIGHT, ref npValue);
                    break;
                case "IKP_DATA_FORMAT":
                    // Get data format
                    IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_DATA_FORMAT, ref npValue);
                    if (npValue != 8)
                    {
                        npValue = 16;
                    }
                    break;
                case "IKP_IMAGE_TYPE":
                    // Get image type
                    IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_TYPE, ref npValue);
                    // Get format value
                    switch (npValue)
                    {
                        case 0:
                            npValue = 1;
                            break;
                        case 2:
                        case 4:
                            npValue = 4;
                            break;
                        default:
                            npValue = 3;
                            break;
                    }
                    break;
                case "IKP_FRAME_COUNT":
                    IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_COUNT, ref npValue);
                    break;
                case "IKP_FRAME_SIZE":
                    IKapBoard.IKapGetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_SIZE, ref npValue);
                    break;
                default:
                    break;
            }
            return npValue;
        }

        public override void SetParameter(string uType, double nValue)
        {
            switch (uType)
            {
                case "IKP_IMAGE_HEIGHT":
                    // Set image height
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_IMAGE_HEIGHT, (int)nValue);
                    break;
                case "IKP_FRAME_COUNT":
                    // Configure image buffers
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_COUNT, (int)nValue);
                    break;
                case "IKP_TIME_OUT":
                    // Configure timeout
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_TIME_OUT, (int)nValue);
                    break;
                case "IKP_GRAB_MODE":
                    // Configure grab start mode
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_GRAB_MODE, (int)nValue);
                    break;
                case "IKP_FRAME_TRANSFER_MODE":
                    // Configure transfer mode
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, (int)nValue);
                    break;
                case "IKP_BOARD_TRIGGER_MODE":
                    // Set board frame trigger parameter
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_BOARD_TRIGGER_MODE, (int)nValue);
                    break;
                case "IKP_BOARD_TRIGGER_SOURCE":
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_BOARD_TRIGGER_SOURCE, (int)nValue);
                    break;
                case "IKP_CC1_SOURCE":
                    // Set board line trigger parameter
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_CC1_SOURCE, (int)nValue);
                    break;
                case "IKP_INTEGRATION_TRIGGER_SOURCE":
                    IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_INTEGRATION_TRIGGER_SOURCE, (int)nValue);
                    break;
                default:
                    break;
            }
        }

        public override void UserSave()
        {

        }

        public override void LoadConfigurationFromFile(string lpFileName)
        {
            IKapBoard.IKapLoadConfigurationFromFile(m_hBoard, lpFileName);
            // Configure image buffers
            IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_COUNT, m_nTotalFrameCount);
            // Configure timeout
            IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_TIME_OUT, -1);
            // Configure grab start mode
            IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_GRAB_MODE, (int)GrabMode.IKP_GRAB_NON_BLOCK);
            // Configure transfer mode
            IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT);
            OnGrabStartProc = new IKapCallBackProc(OnGrabStartFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStart, Marshal.GetFunctionPointerForDelegate(OnGrabStartProc), m_hBoard);
            OnFrameReadyProc = new IKapCallBackProc(OnFrameReadyFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameReady, Marshal.GetFunctionPointerForDelegate(OnFrameReadyProc), m_hBoard);
            OnFrameLostProc = new IKapCallBackProc(OnFrameLostFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameLost, Marshal.GetFunctionPointerForDelegate(OnFrameLostProc), m_hBoard);
            OnTimeoutProc = new IKapCallBackProc(OnTimeoutFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_TimeOut, Marshal.GetFunctionPointerForDelegate(OnTimeoutProc), m_hBoard);
            OnGrabStopProc = new IKapCallBackProc(OnGrabStopFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStop, Marshal.GetFunctionPointerForDelegate(OnGrabStopProc), m_hBoard);
            // Register Callback	
            OnGrabLineEndProc = new IKapCallBackProc(OnGrabLineEndFunc);
            for (uint i = 1; i < 5; ++i)
            {
                IKapBoard.IKapRegisterCallback(m_hBoard, (uint)(CallBackEvents.IKEvent_GrabLineEnd + i * 200), Marshal.GetFunctionPointerForDelegate(OnGrabLineEndProc), m_hBoard);
            }
            OnGeneralInput1FallingEdgeProc = new IKapCallBackProc(OnGeneralInput1FallingEdgeFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_INPUT_FALLING_EDGE + 0x02, Marshal.GetFunctionPointerForDelegate(OnGeneralInput1FallingEdgeProc), m_hBoard);
            OnGeneralInput1RisingEdgeProc = new IKapCallBackProc(OnGeneralInput1RisingEdgeFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEVENT_INPUT_RISING_EDGE + 0x02, Marshal.GetFunctionPointerForDelegate(OnGeneralInput1RisingEdgeProc), m_hBoard);
            OnGeneralInput2FallingEdgeProc = new IKapCallBackProc(OnGeneralInput2FallingEdgeFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_INPUT_FALLING_EDGE + 0x04, Marshal.GetFunctionPointerForDelegate(OnGeneralInput2FallingEdgeProc), m_hBoard);
            OnGeneralInput2RisingEdgeProc = new IKapCallBackProc(OnGeneralInput2RisingEdgeFunc);
            IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEVENT_INPUT_RISING_EDGE + 0x04, Marshal.GetFunctionPointerForDelegate(OnGeneralInput2RisingEdgeProc), m_hBoard);
        }
    }
}
